package org.agony2d.gpu.core {
	import flash.geom.Matrix;
	import flash.geom.Rectangle
	import flash.utils.Dictionary;
	import org.agony2d.debug.Logger
	import org.agony2d.core.agony_internal
	import org.agony2d.gpu.ImageAA;
	import org.agony2d.gpu.StateGroupAA;
	import org.agony2d.input.ATouchEvent;
	import org.agony2d.input.Touch;
	import org.agony2d.input.TouchManager;
	import org.agony2d.notify.AEvent;
	
	use namespace agony_internal;
	
	/** [ NodeAA ]
	 *  [◆◆]
	 *  	1.  reset
	 *  	2.  exit
	 *  	3.  createLayer
	 *  	4.  getLayerAt
	 */
public class WorldAA extends NodeAA {
	
	public function WorldAA( width:int, height:int, invalidWhenLeave:Boolean ) {
		m_worldWidth = width < 0 ? g_fullWidth : width
		m_worldHeight = height < 0 ? g_fullHeight : height
		m_invalidWhenLeave = invalidWhenLeave
	}
	
	public function get numLayers() : int {
		return m_numLayers
	}
	
	public function reset() : void {
		var i:int
		
		while (i < m_numLayers) {
			m_layerList[i++].reset()
		}
	}
	
	public function exit() : void {
		var i:int
		
		while (i < m_numLayers) {
			m_layerList[i++].stop()
		}
	}
	
	public function createLayer( stateAARef:Class ) : StateGroupAA {
		var layer:StateGroupAA
		
		m_layerList[m_numLayers++] = layer = new StateGroupAA(new stateAARef)
		layer.m_world = this
		layer.m_parent = this
		return layer
	}
	
	public function getLayerAt( index:int ) : StateGroupAA {
		return m_layerList[index]
	}
	
	override public function kill() : void {
		AAManager.removeWorld(this)
		this.dispose()
	}
	
	override public function set pivotX( v:Number ) : void {
		Logger.reportError(this, "pivotX", "non useful...!!")
	}
	
	override public function set pivotY( v:Number ) : void {
		Logger.reportError(this, "pivotY", "non useful...!!")
	}
	
	override public function set rotation( v:Number ) : void {
		Logger.reportError(this, "rotation", "non useful...!!")
	}
	
	override public function set scaleX( v:Number ) : void {
		Logger.reportError(this, "scaleX", "non useful...!!")
	}
	
	override public function set scaleY( v:Number ) : void {
		Logger.reportError(this, "scaleY", "non useful...!!")
	}
	
	override public function setCollisionMethod( v:Function ) : void {
		Logger.reportError(this, "setCollisionMethod", "non useful...!!")
	}
	
	override public function collide( x:Number, y:Number, global:Boolean = true ) : Boolean {
		return this.checkCollisionNode(x, y, false)
	}
	
	
	
	agony_internal static var g_scissorRect:Rectangle = new Rectangle
	
	agony_internal var m_layerList:Array = []
	agony_internal var m_numLayers:int
	agony_internal var m_worldWidth:int, m_worldHeight:int
	agony_internal var m_currTouch:Touch
	agony_internal var m_touchMap:Dictionary = new Dictionary // Touch:ImageAA
	agony_internal var m_invalidWhenLeave:Boolean
	
	override agony_internal function dispose() : void {
		var i:int
		
		super.dispose()
		while (i < m_numLayers) {
			m_layerList[i++].dispose()
		}
	}
	
	override agony_internal function render( vertexChanged:Boolean, tinted:Boolean ) : void {
		var i:int
		var layer:GroupAA
		var scissorEnabled:Boolean
		
		scissorEnabled = m_x != 0 || m_y != 0 || m_worldWidth != g_fullWidth || m_worldHeight != g_fullHeight
		if (scissorEnabled) {
			g_scissorRect.setTo(m_x, m_y, m_worldWidth, m_worldHeight)
			g_context3d.setScissorRectangle(g_scissorRect)
		}
		if (m_altered) {
			this.updateNodeMatrix()
			vertexChanged = true
		}
		g_matrixQueue.copyFrom(m_matrix)
		while (i < m_numLayers) {
			m_layerList[i++].render(vertexChanged, false)
		}
		if (scissorEnabled) {
			g_context3d.setScissorRectangle(null)
		}
		
		//Logger.reportMessage(this, "draw count: " + g_drawCount)
		//g_drawCount = 0
	}
	
	override agony_internal function removeNode( node:NodeAA ) : void {
		var index:int
		
		index = m_layerList.indexOf(node)
		m_layerList.splice(index, 1)
		--m_numLayers
	}
	
	override agony_internal function checkCollisionNode( localX:Number, localY:Number, forInteract:Boolean ) : NodeAA {
		var layer:GroupAA
		var node:NodeAA
		var matrix:Matrix
		var l:int
		
		if (forInteract && m_intouchable) {
			return null
		}
		l = m_numLayers
		matrix = cachedMatrix
		while (--l > -1) {
			layer = m_layerList[l]
			matrix.copyFrom(layer.m_matrix)
			matrix.invert()
			node = layer.checkCollisionNode(localX - m_x, localY - m_y, forInteract)
			if (node) {
				return node
			}
		}
		return null
	}
	
	agony_internal function handleInteract( touch:Touch, type:String ) : void {
		var imgA:ImageAABase, imgB:ImageAABase, imgH:ImageAABase
		var group:GroupAA
		var node:NodeAA
		var l:int
		var outOfBounds:Boolean
		var localX:Number, localY:Number
		
		localX = touch.m_stageX
		localY = touch.m_stageY
		outOfBounds = localX < m_x || localX > m_x + m_worldWidth || localY < m_y || localY > m_y + m_worldHeight
		imgB = m_touchMap[touch]
		m_currTouch = touch
		if (imgB || type == ATouchEvent.NEW_TOUCH) {
			imgA = this.checkCollisionNode(localX, localY, true) as ImageAA
			if (imgA) {
				if (type == ATouchEvent.NEW_TOUCH) {
					if (!imgA.m_bindingTouch && !outOfBounds) {
						m_touchMap[touch] = imgA.m_bindingHoverNode = imgA
						imgA.m_bindingTouch = touch
						imgA.bubble(AEvent.PRESS, true)
						//trace(AEvent.PRESS)
						return
					}
				}
				else if (type == AEvent.RELEASE) {
					if (imgA == imgB && !TouchManager.g_allInvalid && !outOfBounds) {
						imgA.bubble(AEvent.CLICK, false)
					}
					else if (!imgA.m_bindingTouch && !outOfBounds) {
						imgA.bubble(type, false)
					}
					imgB.bubble(type, true)
					delete m_touchMap[touch]
					imgB.m_bindingTouch = null
					imgB.m_bindingHoverNode = null
					//trace(AEvent.RELEASE)
					return
				}
				else if (type == AEvent.MOVE) {
					imgH = imgB.m_bindingHoverNode
					if (!outOfBounds) {
						imgA.bubble(type, true)
					}
					if (imgA != imgH) {
						if ((imgA == imgB || imgA.m_bindingTouch) && !outOfBounds) {
							imgB.m_bindingHoverNode = imgA
							imgA.bubble(AEvent.OVER, false)
						}
						if (imgH) {
							if ((imgH == imgB || imgH.m_bindingTouch) && !imgH.m_dead) {
								imgH.bubble(AEvent.LEAVE, false)
							}
							if (m_invalidWhenLeave && imgA != imgB) {
								delete m_touchMap[touch]
								imgB.m_bindingTouch = null
								imgB.m_bindingHoverNode = null
							}
						}
					}
					//trace(AEvent.MOVE)
					return
				}
			}
		}
		if (type == AEvent.MOVE && imgB) {
			imgH = imgB.m_bindingHoverNode
			if (imgH) {
				if ((imgH == imgB || imgH.m_bindingTouch) && !imgH.m_dead) {
					imgH.bubble(AEvent.LEAVE, false)
				}
				imgB.m_bindingHoverNode = null
				if (m_invalidWhenLeave) {
					delete m_touchMap[touch]
					imgB.m_bindingTouch = null
				}
			}
		}
		else if (type == AEvent.RELEASE) {
			if (imgB) {
				imgB.bubble(type, false)
				delete m_touchMap[touch]
				imgB.m_bindingTouch = null
				imgB.m_bindingHoverNode = null
				//trace(AEvent.RELEASE)
			}
		}
		else if (type == ATouchEvent.NEW_TOUCH) {
			type = AEvent.PRESS
		}
		if (!outOfBounds) {
			this.dispatchDirectEvent(type)
			//trace(type)
		}
		m_currTouch = null
	}
}
}